#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <time.h> 
#include <stdint.h>
#include "util.h"
#include <inttypes.h>

/********************************************************
  这个是SS进程。其与TGS加密通信的密钥为0x4142434445464748，
  即可见字符串"ABCDEFGH"的ASCII。
*********************************************************/
#define K_SS 0x4142434445464748

int main() {
    srand(time(NULL));
    int listenfd = 0, connfd = 0;
    struct sockaddr_in serv_addr, client_addr;

    listenfd = socket(AF_INET, SOCK_STREAM, 0);
    memset(&serv_addr, 0, sizeof(serv_addr));

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    serv_addr.sin_port = htons(33333); 

    int res = bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); 
    if (res != 0) {
        printf("errno %d: %s\n", errno, strerror(errno));
        return 1;
    }

    listen(listenfd, 10); 

    int client_len = sizeof(struct sockaddr_in);
    char client_ip[20];
    char client_ip_port[30];
    printf("Service server started!\n");
    while (1) {
        printf("Listening...\n");
        connfd = accept(listenfd, (struct sockaddr*)&client_addr, (socklen_t*)&client_len); 
        inet_ntop(AF_INET, &client_addr.sin_addr, client_ip, sizeof(client_ip));
        sprintf(client_ip_port, "%s:%d", client_ip, ntohs(client_addr.sin_port));
        printf("Accepted %s\n", client_ip_port);

        /* 接收EG两则消息 */
        multi_msg message_eg = new_multi_msg();
        mm_sock_read(&message_eg, connfd);
        /* 提取并解密ST */
        multi_msg message_e = new_multi_msg();
        mm_loads(&message_e, message_eg.msgs + 0);
        multi_msg message_st = new_multi_msg();
        mm_decrypt_loads(&message_st, message_e.msgs + 1, K_SS);
        mm_free(&message_e);
        printf("(Decrypted from ST) Client ID: %s\n", message_st.msgs[0].data);
        printf("(Decrypted from ST) Client address when connecting to TGS: %s\n", message_st.msgs[1].data);
        uint64_t k_client_ss = 0;
        for (int i = 0; i < 8; ++i) {
            k_client_ss |= ((uint64_t)message_st.msgs[2].data[i] << (i * 8));
        }
        printf("(Decrypted from ST) k_client_ss: %016" PRIx64 "\n", k_client_ss);

        /* 用从ST中解密获得的k_client_ss解密G中的client ID和timestamp */
        multi_msg message_g = new_multi_msg();
        mm_decrypt_loads(&message_g, message_eg.msgs + 1, k_client_ss);
        mm_free(&message_eg);
        printf("(Decrypted from G) Client ID: %s\n", message_g.msgs[0].data);
        uint32_t stamp = 0;
        for (int i = 0; i < 4; ++i) {
            stamp |= ((uint32_t)message_g.msgs[1].data[i] << (i * 8));
        }
        printf("(Decrypted from G) Timestamp: %" PRIu32 "\n", stamp);




        /* 现在SS已经信任Client的身份了，返回H是为了让Client也信任自己 */
        multi_msg message_final = new_multi_msg();
        if (strcmp((char*)message_st.msgs[0].data, (char*)message_g.msgs[0].data) == 0) {   // 认证成功
            multi_msg message_h = new_multi_msg();
            mm_build(&message_h, "sd", message_st.msgs[0].data, stamp + 1);
            octet_string eos_h = new_octet_string();
            mm_dumps_encrypt(&eos_h, &message_h, k_client_ss);
            mm_free(&message_h);

            mm_build(&message_final, "so", "success", &eos_h);
        }
        else {  // 认证失败
            mm_build(&message_final, "s", "fail");
        }
        mm_sock_write(connfd, &message_final);
        mm_free(&message_final);
        mm_free(&message_st);
        mm_free(&message_g);




        /* 开始为Client提供转大写服务 */
        printf("Start serving.\n");
        while (1) {
            multi_msg message_cipher = new_multi_msg();
            mm_sock_read(&message_cipher, connfd);
            multi_msg message_test = new_multi_msg();
            mm_decrypt_loads(&message_test, message_cipher.msgs + 0, k_client_ss);
            mm_free(&message_cipher);

            char *str = (char*)message_test.msgs[0].data;
            for (size_t i = 0; str[i]; ++i) {
                if (str[i] >= 'a' && str[i] <= 'z') {
                    str[i] = str[i] - 'a' + 'A';
                }
            }
            octet_string eos_test = new_octet_string();
            mm_dumps_encrypt(&eos_test, &message_test, k_client_ss);
            mm_build(&message_cipher, "o", &eos_test);
            mm_sock_write(connfd, &message_cipher);

            size_t num = message_test.num;
            mm_free(&message_test);
            if (num > 1) {
                break;
            }
        }


        close(connfd);
        sleep(1);
        putchar('\n');
     }
}
